import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

///flutter 生命周期
///https://blog.csdn.net/brycegao321/article/details/86583223
///

class LifeCycleWidget extends StatefulWidget {
  @override
  _LifeCycleWidgetState createState() => _LifeCycleWidgetState();
}

class _LifeCycleWidgetState extends State<LifeCycleWidget>
    with WidgetsBindingObserver {
  @override
  void initState() {
    print("_LifeCycleWidgetState initState");
    //插入到渲染树时调用，只执行一次。（类似Android Fragment的onCreateView函数）
    //当此对象插入树中时调用，框架会调用一次此方法并不会再次重复执行， 如果[State]的[build]方法依赖于本身可以更改状态的对象，
    //例如[ChangeNotifier]或[Stream]， 或者某些其他可以订阅的对象接收通知，可以在此方法订阅，但记得去dispose取消订阅；
    super.initState();

    WidgetsBinding.instance.addObserver(this);

    //addPostFrameCallback是 StatefulWidge 渲染结束的回调，只会被调用一次，
    //之后 StatefulWidget 需要刷新 UI 也不会被调用，addPostFrameCallback的使用方法是在 initState里添加回调：
    SchedulerBinding.instance.addPostFrameCallback((_) => {});
  }

  @override
  void didChangeDependencies() {
    print("_LifeCycleWidgetState didChangeDependencies");
    //1、在初始化initState后执行； 2、显示/关闭其它widget。 3、可执行多次；
    //顾名思义，依赖项更改时调用，但也会在initState之后调用， 在这个方法调用[BuildContext.inheritFromWidgetOfExactType]是安全的。
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    print("_LifeCycleWidgetState build");
    //会在以下场景调用：
    //initState()之后； didUpdateWidget()之后； setState()之后。
    //didChangeDependencies()之后。
    //* State对象从树中一个位置移除后会调用deactivate，然后又重新插入到树的其它位置之后。
    return Container();
  }

  @override
  void didUpdateWidget(covariant LifeCycleWidget oldWidget) {
    print("_LifeCycleWidgetState didUpdateWidget");
    //上级节点rebuild widget时， 即上级组件状态发生变化时会触发子widget执行didUpdateWidget;
    //当组件的状态改变的时候就会调用didUpdateWidget(),比如调用了setState()，
    //在widget重新构建时，Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点，
    //然后决定是否需要更新，如果Widget.canUpdate返回true则会调用此回调。
    //正如之前所述，Widget.canUpdate会在 新旧widget的key和runtimeType同时相等时会返回true，
    //也就是说在新旧widget的key和runtimeType同时相等时didUpdateWidget()就会被调用。
    super.didUpdateWidget(oldWidget);
  }

  @override
  void reassemble() {
    print("_LifeCycleWidgetState reassemble");
    //点击闪电会执行，只用于调试时的hot reload。 release版本不会执行该函数。
    super.reassemble();
  }

  @override
  void deactivate() {
    print("_LifeCycleWidgetState deactivate");
    //有点像Android的onStop函数， 在打开新的Widget或回到这个widget时会执行； 可执行多次；
    //State对象从树中被移除时（在dispose之前），会调用这个函数来将对象暂停
    super.deactivate();
  }

  @override
  void dispose() {
    print("_LifeCycleWidgetState dispose");
    //类似于Android的onDestroy， 在执行Navigator.pop后会调用该办法， 表示组件已销毁；
    //当State对象被销毁时调用，通常在此回调中释放资源和移除监听。
    super.dispose();

    WidgetsBinding.instance.removeObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    //监听特殊状态
    print('特殊状态 state：$state');
  }
}

///总结
//Flutter生命周期可以分为3个阶段：
//1、实例化组件并添加到树， 即Navigator.push；
//2、状态变化，即打开新的widget或者依赖的上级widget发生变化；
//3、从树中移除,  即Navigator.pop。

//为什么将State和Widget分开呢？
//答案是性能， State管理状态（可以理解为Controller），Widget是UI（即View)。 根据状态变化每次生成Widget(即View）可以节省内存，即不必每次创建状态对象State。

//场景：Widget A打开Widget B： Navigator.push(B)
//B构造函数--->B initState--->B didChangeDependencies--->B build--->A deactive--->A didChangeDependencies.
//Widget B退出： Navigator.pop
//A deactive--->A didChangeDependencies--->A build--->B deactive--->B dispose

//场景：打开APP
//initState -> didChangeDependencies -> reassemble -> didUpdateWidget

//场景：热更新
//reassemble -》 didUpdateWidget

//场景：setState
//build

//activity生命周期和Flutter对应关系：
//Flutter提供了WidgetsBindingObserver来监听AppLifecycleState， 而AppLifecycleState有4种状态：
//1、 resumed 界面可见， 同安卓的onResume。
//2、inactive界面退到后台或弹出对话框情况下， 即失去了焦点但仍可以执行drawframe回调；同安卓的onPause；
//3、paused应用挂起，比如退到后台，失去了焦点且不会收到drawframe回调；同安卓的onStop；
//4、suspending， iOS中没用，安卓里就是挂起，不会再执行drawframe回调；
//
//下面是生命周期：
//1、初次打开widget时，不执行AppLifecycleState的回调；
//2、按home键或Power键， AppLifecycleState inactive---->AppLifecycleState pause
//3、从后台到前台：AppLifecycleState inactive--->ApplifecycleState resumed
//4、back键退出应用： AppLifecycleState inactive--->AppLifecycleState paused
//
